﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using NUnit.Framework;
using Smith.AMC;
using Smith.AMC.Configuration;
using Smith.AMC.Network;

namespace MemcachedClientTests
{
    [TestFixture]
    public class CheckAndSetTest
    {
        private List<KeyValuePair<IPAddress, int>> servers = new List<KeyValuePair<IPAddress, int>>();
        private ServerNodeMonitorConfiguration config = new ServerNodeMonitorConfiguration();
        ServerPool pool;
        MemcachedClient client;

        [TestFixtureSetUp]
        public void PerTestSetUp()
        {

            servers.Add(new KeyValuePair<IPAddress, int>(IPAddress.Parse("127.0.0.1"), 11211));
            pool = new ServerPool(servers, SocketType.Stream, ProtocolType.Tcp, 25, config);
            client = new MemcachedClient(new SocketWorker(pool, TimeSpan.FromSeconds(20)));
        }
        
        [Test]
        public void CheckAndSetShouldSetIfCASMatches()
        {
            ICacheItem<long> cacheItem = new CacheItem<long>
            {
                CacheKey = Guid.NewGuid().ToString(),
                LifeTime = TimeSpan.FromSeconds(0),
                Value = 1234567890
            };

            IAsyncResult ar = client.BeginAdd(cacheItem, null, null);
            client.EndAdd<long>(ar);

            ar  = client.BeginGets<long>(cacheItem.CacheKey, null, null);
            ICacheItem<long> retrievedItem = client.EndGets<long>(ar);

            Assert.That(retrievedItem.CASValue, Is.GreaterThan(0));
            
            // Set CAS value and change value
            cacheItem.CASValue = retrievedItem.CASValue;
            cacheItem.Value = 123;

            ar = client.BeginCheckAndSet(cacheItem, null, null);
            bool casSuccess = client.EndCheckAndSet<long>(ar);
            Assert.That(casSuccess, Is.True);

            ar = client.BeginGet<long>(cacheItem.CacheKey, null, null);
            ICacheItem<long> afterGet = client.EndGet<long>(ar);
            Assert.That(afterGet.Value, Is.EqualTo(cacheItem.Value));

        }

        [Test]
        public void CheckAndSetShouldNotSetValueIfCasDoesNotMatch()
        {
            const long initialValue = 1234567890;
            ICacheItem<long> cacheItem = new CacheItem<long>
            {
                CacheKey = Guid.NewGuid().ToString(),
                LifeTime = TimeSpan.FromSeconds(0),
                Value = initialValue
            };

            IAsyncResult ar = client.BeginAdd(cacheItem, null, null);
            client.EndAdd<long>(ar);

            ar = client.BeginGets<long>(cacheItem.CacheKey, null, null);
            ICacheItem<long> retrievedItem = client.EndGets<long>(ar);

            Assert.That(retrievedItem.CASValue, Is.GreaterThan(0));

            // Set CAS value to something invalid and change value
            cacheItem.CASValue = retrievedItem.CASValue+1;
            cacheItem.Value = 123;

            ar = client.BeginCheckAndSet(cacheItem, null, null);
            bool casSuccess = client.EndCheckAndSet<long>(ar);
            Assert.That(casSuccess, Is.False);

            ar = client.BeginGet<long>(cacheItem.CacheKey, null, null);
            ICacheItem<long> afterGet = client.EndGet<long>(ar);
            Assert.That(afterGet.Value, Is.EqualTo(initialValue));
        }
    }
}
